import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { User } from './user.entity';
import { Logs } from '../logs/logs.entity';
import { getUserDto } from './dto/get-user.dto';
import { conditionUtils } from '../../utils/db.helper';
import { Roles } from '../roles/roles.entity';
import * as argon2 from 'argon2';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
    @InjectRepository(Logs)
    private logsRepository: Repository<Logs>,
    @InjectRepository(Roles)
    private rolesRepository: Repository<Roles>,
  ) { }

  findAll(query: getUserDto) {
    const { limit, page, username, gender, role } = query;
    const take = limit || 10;
    const skip = ((page || 1) - 1) * take;

    const queryBuilder = this.userRepository
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.profile', 'profile')
      .leftJoinAndSelect('user.roles', 'roles')
    const obj = {
      'user.username': username,
      'profile.gender': gender,
      'roles.id': role
    }
    const newQuery = conditionUtils<User>(queryBuilder, obj)
    return newQuery
     .take(take)
     .skip(skip)
     .getMany();
  }

  find(username: string) {
    return this.userRepository.findOne({
      where: { username },
      relations: ['roles', 'roles.menus']
     });
  }

  findByUsername(username: string) {
    return this.userRepository.findOne({
      where: { username },
      relations: ['roles']
     });
  }

  findOne(id: number) {
    return this.userRepository.findOne({ where: { id } });
  }

  async create(user: Partial<User>) {
    if (!user.roles){
      const role = await this.rolesRepository.findOne({
        where: { id: 2 }
      });
      user.roles = [role];
    }
    if (user.roles instanceof Array && typeof user.roles[0] === 'number') {
      // 查询用户角色
      user.roles = await this.rolesRepository.find({
        where: {
          id: In(user.roles)
        }
      });
    }
    const userTmp = await this.userRepository.create(user);
    // 使用argon2加密用户密码
    userTmp.password = await argon2.hash(userTmp.password);
    return this.userRepository.save(userTmp);
    // try {
    //   return this.userRepository.save(userTmp);
    // } catch (error) {
    //   console.log("🚀 ~ UserService ~ create ~ error:", error)
    //   if (error.errno && error.errno === 1062) {
    //     throw new HttpException(error.sqlMessage, 500)
    //   }
    // }
  }

  async update(id: number, user: Partial<User>) {
    user.roles = [];
    const userProfile = await this.findProfile(id);
    const userRoles = await this.findRoles(id);
    const newUser = this.userRepository.merge(userProfile, userRoles, user);
    // 联合模型更新，需要使用 save 方法或者 queryBuilder 的 update 方法
    return this.userRepository.save(newUser);

    // 下面的 update 方法，只适合单模型的更新，不适合有关系的模型更新
    // return this.userRepository.update(id, user);
  }

  async remove(id: number): Promise<User> {
    // return this.userRepository.delete(id);
    const user = await this.findOne(id);
    return this.userRepository.remove(user);
  }

  findProfile(id: number) {
    return this.userRepository.findOne({
      where: { id },
      relations: {
        profile: true
      }
    })
  }

  findRoles(id: number) {
    return this.userRepository.findOne({
      where: { id },
      relations: {
        roles: true
      }
    })
  }

  async findUserLogs(id: number) {
    const user = await this.findOne(id);
    return this.logsRepository.find({
      where: { user: user.logs },
      // relations: {
      //   user: true
      // }
    })
  }

  findLogsByGroup(id: number) {
    return this.logsRepository
      .createQueryBuilder('logs')
      .select('logs.result', 'result')
      .addSelect('COUNT("logs.result")', 'count')
      .leftJoinAndSelect('logs.user', 'user')
      .where('user.id = :id', { id })
      .groupBy('logs.result')
      .getRawMany();
  }
}
